package cn.yeziji.forum.dao.iquery;

import cn.org.atool.fluent.mybatis.If;
import cn.org.atool.fluent.mybatis.base.crud.IQuery;
import cn.org.atool.fluent.mybatis.base.crud.JoinBuilder;
import cn.yeziji.forum.dto.details.ForumDetailDTO;
import cn.yeziji.forum.dto.details.ForumDetailPagingDTO;
import cn.yeziji.forum.dto.user.ForumUserDTO;
import cn.yeziji.forum.entity.ForumDetailsEntity;
import cn.yeziji.forum.mapper.ForumUserDetailMapper;
import cn.yeziji.forum.utils.ObjectUtils;
import cn.yeziji.forum.wrapper.ForumDetailsQuery;
import cn.yeziji.forum.wrapper.ForumSpecialColumnQuery;
import cn.yeziji.forum.wrapper.ForumUserDetailQuery;
import cn.yeziji.forum.wrapper.ForumUserQuery;
import cn.yzj.common.CommonSymbol;
import cn.yzj.utils.DataUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.function.Predicate;

/**
 * 查询构造器
 *
 * <p>要运用用户 id 进行查询时，传入 isDelete，当 isDelete 不为 null 时添加 eq 条件
 *
 * @author gzkemays
 * @since 2022/3/16
 */
@Component
public class DetailQuery {
  public static String SERIAL_NUMBER_KEY = "serialNumber";
  @Resource ForumUserDetailMapper userDetailMapper;

  public IQuery<ForumDetailsEntity> getUser7DaysDetails(Integer userId) {
    return new ForumDetailsQuery("fd")
        .selectAll()
        .where
        .userId()
        .eq(userId)
        .and(
            q ->
                q.where
                    .applyFunc(
                        "DATE_SUB(CURDATE(), INTERVAL 7 DAY) <= date(fd.createTime) or DATE_SUB(CURDATE(), INTERVAL 7 DAY) <= date(fd.updateTime)")
                    .end())
        .end();
  }
  /**
   * 根据 id 获取 view 和文章状态的条件构造器
   *
   * @param id 文章id
   */
  public IQuery<ForumDetailsEntity> getViewAndTempSaveStatusByIdQuery(int id) {
    return new ForumDetailsQuery().select.view().tempSave().end().where.id().eq(id).end();
  }
  /** 已发布文章数量查询构造器 */
  public IQuery<ForumDetailsEntity> publisedSerialQuery() {
    return new ForumDetailsQuery()
        .select
        .serialNumber()
        .end()
        .where
        .tempSave()
        .isFalse()
        .and
        .delete()
        .isFalse()
        .end();
  }

  /**
   * 根据一篇的文章ID搜索与其相关的专栏文章ID列表
   *
   * @param specialId 专栏id
   * @param userId 专栏的用户id
   */
  public IQuery<ForumDetailsEntity> findSpecialDetailsQuery(Object specialId, Object userId) {
    return new ForumDetailsQuery()
        .select
        .id()
        .title()
        .desc()
        .end()
        .where
        .specialId()
        .eq(specialId)
        .and
        .userId()
        .eq(userId)
        .end()
        .orderBy
        .createTime()
        .desc()
        .updateTime()
        .desc()
        .end();
  }

  /**
   * 删除或恢复的单对象查询构造器
   *
   * @param dto 文章值对象
   * @param userId 用户 id
   */
  public IQuery<ForumDetailsEntity> delOrRecoveryOneQuery(ForumDetailDTO dto, int userId) {
    return new ForumDetailsQuery().where.userId().eq(userId).and.id().eq(dto.getId()).end();
  }

  /**
   * 获取单个文章数据的条件构造器
   *
   * @param dto 文章值对象
   * @param userId 用户 id
   */
  public IQuery getOneQuery(ForumDetailDTO dto, int userId) {
    return JoinBuilder.from(
            new ForumDetailsQuery()
                .select
                .id()
                .userId("authorId")
                .specialId()
                .author()
                .title()
                .content()
                .desc()
                .tags()
                .goodNumber()
                .commentNumber()
                .collectionNumber()
                .serialNumber()
                .createTime()
                .autoFormat()
                .view()
                .aveRate()
                .updateTime("publishTime")
                .end()
                .where
                .id()
                .eq(dto.getId())
                .end())
        .leftJoin(
            new ForumUserDetailQuery()
                .select
                //                .userId()
                .toGood()
                .toComment()
                .toCollection()
                .toRate()
                .end())
        .on(l -> l.where.id(), r -> r.where.detailId())
        .onRight(r -> r.where.userId().eq(userId))
        .endJoin()
        .leftJoin(new ForumSpecialColumnQuery().select.name("special").end())
        .on(l -> l.where.specialId(), r -> r.where.id())
        .endJoin()
        .leftJoin(new ForumUserQuery().select.desc("authorDesc").avatar().end())
        .on(l -> l.where.userId(), r -> r.where.id())
        .endJoin()
        .build();
  }
  /**
   * 获取文章的数量构造器
   *
   * @param dto 前端传入文章值对象
   */
  public IQuery<ForumDetailsEntity> getListCountQuery(Integer userId, ForumDetailPagingDTO dto) {
    Boolean tempSave = dto.getTempSave();
    Boolean isDelete = dto.getDelete() != null && dto.getDelete();
    Predicate<Integer> userIdPredicate =
        (uId) -> dto.getTempSave() != null && dto.getDelete() != null;
    return new ForumDetailsQuery()
        .where
        .tempSave()
        .eq(tempSave, If::notNull)
        .and
        .delete()
        .eq(isDelete)
        .and
        .userId()
        .eq(userId, userIdPredicate)
        .end();
  }
  /**
   * 构建 list 查询构造器
   *
   * @param userId 用户id
   * @param dto dto 查询对象
   * @return 文章list查询构造器
   */
  public IQuery getListQuery(ForumDetailPagingDTO dto, int userId) {
    String title = dto.getTitle();
    String special = "", author = "", blurTitle = "";
    if (StringUtils.hasText(title)) {
      if (title.startsWith(CommonSymbol.NUMBER_SIGN)) {
        int dollar = title.indexOf(CommonSymbol.DOLLAR);
        int empty = title.indexOf(" ");
        // 作者
        if (dollar > 0) {
          author =
              empty > 0
                  ? DataUtils.substrBetweenOfFirstAndFirst(title, CommonSymbol.DOLLAR, " ")
                  : DataUtils.substrAfterOfTag(title, CommonSymbol.DOLLAR);
          special =
              DataUtils.substrBetweenOfFirstAndFirst(
                  title, CommonSymbol.NUMBER_SIGN, CommonSymbol.DOLLAR);
        }
        // 获取模糊文章
        if (empty > 0) {
          blurTitle = DataUtils.substrAfterOfTag(title, " ");
          if (special.length() == 0) {
            special = DataUtils.substrBetweenOfFirstAndFirst(title, CommonSymbol.NUMBER_SIGN, " ");
          }
        }

        if (dollar == -1 && empty == -1) {
          special = DataUtils.substrAfterOfTag(title, CommonSymbol.NUMBER_SIGN);
        }
      } else {
        blurTitle = title;
      }
    }
    Integer mode = dto.getMode();
    Boolean tempSave = dto.getTempSave();
    Boolean isDelete = dto.getDelete() != null && dto.getDelete();
    return JoinBuilder.from(
            new ForumDetailsQuery()
                .selectAll()
                .select
                .updateTime("publishTime")
                .end()
                .where
                .tempSave()
                .eq(tempSave, If::notNull)
                .and
                .userId()
                .eq(userId, sw -> dto.getDelete() != null || (tempSave != null && tempSave))
                .and
                .tags()
                .like(dto.getTags(), If::notBlank)
                .and
                .title()
                .like(blurTitle, If::notBlank)
                .and
                .author()
                .like(author, If::notBlank)
                .and
                .delete()
                .eq(isDelete)
                .end()
                .orderBy
                .updateTime()
                .descIf(mode == 0)
                .createTime()
                .descIf(mode == 0)
                .view()
                .descIf(mode == 1)
                .aveRate()
                .descIf(mode == 2)
                .collectionNumber()
                .descIf(mode == 3)
                .goodNumber()
                .descIf(mode == 4)
                .createTime()
                .ascIf(mode == 5)
                .updateTime()
                .ascIf(mode == 5)
                .end())
        .leftJoin(
            new ForumUserDetailQuery()
                .select
                .userId("uid")
                .toGood()
                .toComment()
                .toCollection()
                .toRate()
                .end())
        .on(l -> l.where.id(), r -> r.where.detailId())
        .onRight(q -> q.where.and(and -> and.where.userId().eq(userId).or.userId().isNull().end()))
        .endJoin()
        .leftJoin(
            new ForumSpecialColumnQuery()
                .select
                .name("special")
                .end()
                .where
                .name()
                .eq(special, If::notBlank)
                .end())
        .on(l -> l.where.specialId(), r -> r.where.id())
        .endJoin()
        .limit(dto.prefix(), dto.last())
        .build();
  }

  /** 分类分页查询 */
  public IQuery<ForumDetailsEntity> getListTypeQuery(ForumDetailPagingDTO dto, int userId) {
    ForumDetailsQuery typeQuery = getTypeQuery(dto, userId);
    if (dto.getPage() != 0 && dto.getLimit() != 0) {
      typeQuery.limit(dto.prefix(), dto.last());
    }
    return typeQuery;
  }

  /** 分类查询总数 */
  public IQuery<ForumDetailsEntity> getListTypeQueryCount(ForumDetailPagingDTO dto, int userId) {
    return getTypeQuery(dto, userId);
  }

  /**
   * 统计分类数量的查询构造器
   *
   * @param dto 用户值对象
   */
  public IQuery getStatisticsTypeCountQuery(ForumUserDTO dto) {
    return JoinBuilder.from(
            new ForumDetailsQuery().select.id().end().where.userId().eq(dto.getUserId()).end())
        .rightJoin(
            new ForumUserDetailQuery()
                .select
                .toCollection()
                .toGood()
                .end()
                .where
                .and(q -> q.where.toGood().isTrue().or.toCollection().isTrue().end())
                .end())
        .on(l -> l.where.id(), r -> r.where.detailId())
        .endJoin()
        .build();
  }

  /**
   * 分类查询
   *
   * @param userId 用户id
   * @param dto 文章分页值对象
   * @return 查询构造器
   */
  private ForumDetailsQuery getTypeQuery(ForumDetailPagingDTO dto, int userId) {
    Boolean collection = dto.getCollection();
    Boolean good = dto.getGood();
    boolean openIn =
        (ObjectUtils.nonNullAndEqTarget(collection, true)
            || ObjectUtils.nonNullAndEqTarget(good, true));
    return new ForumDetailsQuery()
        .where
        .id()
        .in(
            new ForumUserDetailQuery()
                .select
                .detailId()
                .end()
                .where
                .userId()
                .eq(userId)
                .and
                .toCollection()
                .eq(collection, c -> ObjectUtils.nonNullAndEqTarget(c, true))
                .and
                .toGood()
                .eq(good, g -> ObjectUtils.nonNullAndEqTarget(g, true))
                .end())
        .and
        .title()
        .like(dto.getTitle(), If::notNull)
        .and
        .userId()
        .eq(userId, toUser -> !openIn)
        .end()
        .limit(dto.prefix(), dto.last());
  }
}
